#ifndef IEDEMCOUPLING
#define IEDEMCOUPLING

#include <limits>
#include <vector>

#include "CContactPrototype.h"
#include "CDiscreteElement.h"
#include "CElementPrototype.h"
#include "CParticleSphere.h"
#include "vectorMaths.h"
#include "ApiTypes.h"
#include "CouplingUtils.h"


#ifdef _WIN32
#   define DLL_INT __declspec(dllexport)
#   define DEPRECATED __declspec(deprecated)
#else
#   define DLL_INT
#   define DEPRECATED
#endif

/**
 * The NApiEDEM namespace contains all interfaces for creating a coupling with EDEM
 */
namespace NApiEDEM
{
    // The "Sent to EDEM:" list indicates the variables that are sent to
    // EDEM in order for processing to take place.
    // The "Return parameters:" list indicates the variables that are returned
    // by EDEM when processing has been completed.

    /** \defgroup Coupling_Interface_4_0_0 Coupling Interface V4_0_0
    * @{
    */

    /**  \ingroup Coupling_Interface_4_0_0 IEDEMCoupling
     *
     * Defines the interface functionality for v4.0.0 of the Coupling Interface
     *
     */
    class DLL_INT IEDEMCoupling
    {

    public:
        /** Default constructor */
        IEDEMCoupling();

        /** Destructor */
        ~IEDEMCoupling();

/////////////////////////////////////////////////////////////////////////////////////////
//                            Coupling Management Commands                             //
/////////////////////////////////////////////////////////////////////////////////////////


        /**
         * Use to initialise the coupling client. This method displays a warning dialog
         * before connection and therefore only suitable for GUI driven applications
         *
         * Returned from EDEM:
         * @return True if initialisation was successful, otherwise false.
         */
        bool initialiseCoupling();

        /**
         * Use to 'reset' the object that handles the traffic between the client and the
         * EDEM server
         * A subsequent call to 're-intialise' the coupling is required prior to any further
         * use of the coupling.
         *
         * @return True if disconnection was successful, otherwise false.
         */
        bool disconnectCoupling();

        /**
         * Connects the coupling to EDEM
         * @param showMsg Determines whether to pop up a warning Gui for connection
         *                  Requires GUI support to choose true.
         * @param ipAddress The network address of the computer to connect to. Default
                              parameter is the localhost IP
         * @return True if connection was successful, otherwise false.
         */
        bool connectCoupling(bool showMsg = false, const char ipAddress[16] = "127.000.000.001");

        /**
         * Provides access to the 'connected' state of the coupling -
         * helper function for use with the client
         *
         * @return True if active connection, otherwise false.
         */
        bool isConnected() const;

        /**
         * Get the last error registered by the Coupling Client. When got, this
         * error is removed and the next prior error is available
         *
         * Returned from EDEM:
         * @return The error as a char*.
         */
        char* getLastError() const;

        /**
         * This function should be used in tandem with the wait flag to enable the
         * client to force EDEM to terminate execution
         *
         * @return True if shutdown was successful, otherwise false.
         */
        bool shutdownEDEM();

        /**
         * Clears all currently recorded errors
         */
        void clearErrors();


/////////////////////////////////////////////////////////////////////////////////////////
//                            Environment Setting Commands                             //
/////////////////////////////////////////////////////////////////////////////////////////


        /**
         * Load a new geometry such as a .msh or .stl file to EDEM, intialising a new deck.
         * EDEM will return a response indicating whether the import was successfully.
         *
         * Sent to EDEM:
         * @param newEDEMDeckName New deck name for EDEM to create, including the full path.
         *        Note: Any existing deck with the same name will be overwritten.
         * @param cadFilename The name of the CAD file to be imported, including the full path
         *
         * Returned from EDEM:
         * @return True if import was successful, otherwise false.
         */
        bool newGeometry(const char* newEDEMDeckName,
                         const char* cadFilename);

        /**
         * Returns the index of a given material for use with the loadGeometry function
         *
         * @param materialName the name of the material to use for the geometry section
         * @return The index of the entry in the list of meterials, -1 if entry not found.
         */
        int getMaterialId(const char* materialName);

        /**
         * Use this function to retrieve a list of the material names contained
         * in the simulation deck.
         * @param materialNames char array, holding the names of the various material types
         * @param materialCount the number materials specified in the simulation
         *
         * @return true / false dependent on operation's success.
         */
        bool getMaterialNames(char**& materialNames, int& materialCount);

        /**
         * Enables various geometry options to be configured prior to
         * invoking the loadGeometry() function
         *
         * @param meshControl "Size and bias"/ "Rigid body" mesh control types for conversion
         * @param elemSize size of the elements used in "Size and bias" ( 0 < value )
         * @param minSize minimum element size for "Rigid body" ( 0 < value < 10.0 )
         * @param maxSize maximum element size for "Rigid body" ( 0.5 < value )
         * @param maxDeviation minimum deviation for  "Rigid body" ( 0 < value )
         * @param maxAngle maximum valid angle for "Rigid body" ( 0 < value < 180.0 )
         *
         * Returned from EDEM:
         * @return True if import was successful, otherwise false.
         */
        bool setGeometryImportParameters(const char* meshControl,
                                         double elemSize,
                                         double minSize,
                                         double maxSize,
                                         double maxDeviation,
                                         double maxAngle);

        /**
         * Add the specified geometry to an existing EDEM deck
         *
         * Sent to EDEM:
         * @param cadFileName Name of the CAD file to be imported, including the full path.
         * @param materialIndex id of the material type to use.
         * @param forcemerge Flag for control of the merge option
         * @param units enum defining the import units used.
         *
         * @return True if import was successful, otherwise false.
         */
        bool loadGeometry(const char* cadFileName,
                          int materialIndex,
                          bool forcemerge,
                          NApi::EGeometryImportUnits units);


        /**
         * Add the specified geometry bin the Analyst's selections
         *
         * Sent to EDEM:
         * @param cadFilename Name of the CAD file to be imported, including the full path.
         * @param forcemerge Flag for control of the merge option
         * @param alignAxes Flag to control the axes alignment
         * @param units enum defining the import units used.
         *
         * @return True if import was successful, otherwise false.
         */
        bool importGeometryBin(const char* cadFilename,
                               bool forcemerge,
                               bool alignAxes,
                               NApi::EGeometryImportUnits units);

        /**
        * Get the names of the various loaded geometry sections.
        *
        * Sent to EDEM:
        * @param sectionNames char array, holding the names of the loaded geometry sections.
        * @param geomSectionCount the number of geometry sections in the simulation
        *
        * @return True if operation was successful, otherwise false.
        */
        bool getGeometrySectionNames(char**& sectionNames, int& geomSectionCount);

        /**
        * Get the Centre of Mass of the selected geometry section.
        *
        * Sent to EDEM:
        * @param geometryId the target geometry's id.
        * @param centreOfMass CoM C3dValue.
        *
        * @return True if operation was successful, otherwise false.
        */
        bool getGeometryCoM(const int geometryId, NApiEDEM::C3dValue& centreOfMass);

        /**
        * set the Centre of Mass of the selected geometry section.
        *
        * Sent to EDEM:
        * @param geometryId the target geometry's id.
        * @param centreOfMass CoM C3dValue.
        *
        * @return True if operation was successful, otherwise false.
        */
        bool setGeometryCoM(const int geometryId, const NApiEDEM::C3dValue& centreOfMass);

        /**
        * Get the Type of the geometry section [Physical | Virtual | Dynamic Domain]
        *
        * Sent to EDEM:
        * @param sectionName the name of the geometry to be updated.
        * @param geometryType (retrieved) 0 == unknown / 1 == physical / 2 == virtual / 3 = dynamic domain.
        *
        * @return True if operation was successful, otherwise false.
        */
        bool getGeometryType(const char* sectionName, int& geometryType);

        /**
        * For a given geometry, get the total number of triangles.
        * Setting id = -1, results will be corresponding to all the geometry groups.
        * A client can also use this function to allocate buffers of the correct size before calling getTrianglesIDsAndForces
        *
        * @param id The target geometry ID
        * @param totalTriangles The total number of triangles of the given geometry.
        *
        * @return True if operation was successful, otherwise false.
        */
        bool getGeometryTotalTriangles(const int id, int& totalTriangles);

        /**
        * For a given geometry, get the total number of nodes.
        * Setting id = -1, results will be corresponding to all the geometry groups.
        * A client can also use this function to allocate buffers of the correct size before calling getNodeIDsAndForces
        *
        * @param id The target geometry ID
        * @param totalNodes The total number of nodes of the given geometry.
        *
        * @return True if operation was successful, otherwise false.
        */
        bool getGeometryTotalNodes(const int id, int& totalNodes);

        /**
        * For a given geometry, get the triangle IDs and their forces.
        * Setting id = -1, results will be corresponding to all the geometry groups.
        *
        * @param id The target geometry ID
        * @param trianglesIDs The triangle IDs of the given geometry.
        * @param trianglesForces The triangle forces of the given geometry.
        *
        * @return True if operation was successful, otherwise false.
        */
        bool getTrianglesIDsAndForces(const int id, int* trianglesIDs, double* trianglesForces);

        /**
        * For a given geometry, get all the node Ids, ordered in the order they are stored inside the geometry.
        *
        * @param id The target geometry ID
        * @param outNodeIds The node ids of the given geometry.
        * @return True if operation was successful, otherwise false.
        */
        bool getNodeIds(const int id, int* outNodeIds);

        /**
        * For a given geometry, get the force vectors being applied the the nodes of the triangle.
        *
        * @param id The target geometry ID
        * @param outNodeForces The node forces of the given geometry.
        * @return True if operation was successful, otherwise false.
        */
        bool getNodeForceVectors(const int id, NApiEDEM::C3dVector* outNodeForces);

       /**
        * Get the indices of the nodes that make up the triangle of triangleID. So you can then work with them in deformation functions and the like
        * @param geomID The ID of the geometry we're looking for. Will fail if geomID dosen't exist in coupled simulation
        * @param triangleID ID of the triangle in question. Will fail if triangleID dosen't exist in geomID
        * @param outNodeIndices Output container. Must be sized to store 3 ints. Filled with the indices of the nodes that make up triangle of triangleID
        * @return True if operation was successful, false if we couldn't find the geometry or the triangle.
        */
        bool getNodeIndicesFromTriangleID(const int geomID, const int triangleID, int* outNodeIndices);

        /**
        * Get a subset of local vertex positions on a geometry
        * @param geomID The ID of the geometry we're looking for. Will fail if geomID dosen't exist in coupled simulation
        * @param positionsOut Output container, is filled with requested positions, must be pre-allocated with correct size.
        * @param numNodes Number of node positions to retreive. Must match the number of elements of positionsOut and nodeIndices
        * @param nodeIndices. Pointer to container of node-indices, these are the nodees that we'll retrieve from the geometry.
        */
        bool getLocalNodePositions(int geomID, NApiEDEM::C3dPoint* positionsOut, int numNodes, const int* nodeIndices) const;

        /**
        * Get a subset of local node velocities on a geometry
        * @param geomID The ID of the geometry we're looking for. Will fail if geomID dosen't exist in coupled simulation
        * @param velocitiesOut Output container, is filled with requested velocities, must be pre-allocated with correct size.
        * @param numNodes Number of node velocities to retreive. Must match the number of elements of velocitiesOut and nodeIndices
        * @param nodeIndices. Pointer to container of node-indices, these are the nodees that we'll retrieve from the geometry.
        */
        bool getLocalNodeVelocities(int geomID, NApiEDEM::C3dVector* velocitiesOut, int numNodes, const int* nodeIndices) const;

        /**
        * Get a subset of global node positions on a geometry
        * @param geomID The ID of the geometry we're looking for. Will fail if geomID dosen't exist in coupled simulation
        * @param positionsOut Output container, is filled with requested positions, must be pre-allocated with correct size.
        * @param numNodes Number of node positions to retreive. Must match the number of elements of positionsOut and nodeIndices
        * @param nodeIndices. Pointer to container of node-indices, these are the nodees that we'll retrieve from the geometry.
        */
        bool getGlobalNodePositions(int geomID, NApiEDEM::C3dPoint* positionsOut, int numNodes, const int* nodeIndices) const;

        /**
        * Get a subset of global node velocities on a geometry
        * @param geomID The ID of the geometry we're looking for. Will fail if geomID dosen't exist in coupled simulation
        * @param velocitiesOut Output container, is filled with requested velocities, must be pre-allocated with correct size.
        * @param numNodes Number of node velocities to retreive. Must match the number of elements of velocitiesOut and nodeIndices
        * @param nodeIndices. Pointer to container of node-indices, these are the nodees that we'll retrieve from the geometry.
        */
        bool getGlobalNodeVelocities(int geomID, NApiEDEM::C3dVector* velocitiesOut, int numNodes, const int* nodeIndices) const;

        /**
        * Get all local node positions on a geometry
        * @param geomID The ID of the geometry we're looking for. Will fail if geomID dosen't exist in coupled simulation
        * @param positionsOut Output container, is filled with all geometry node positions, must be pre-allocated to be as large as the number of nodes in the geometry
        */
        bool getAllLocalNodePositions(int geomID, NApiEDEM::C3dPoint* positionsOut) const;

        /**
        * Get all local node velocities on a geometry
        * @param geomID The ID of the geometry we're looking for. Will fail if geomID dosen't exist in coupled simulation
        * @param velocitiesOut Output container, is filled with all geometry node velocities, must be pre-allocated to be as large as the number of nodes in the geometry
        */
        bool getAllLocalNodeVelocities(int geomID, NApiEDEM::C3dVector* velocitiesOut) const;

        /**
        * Get all global node positions on a geometry
        * @param geomID The ID of the geometry we're looking for. Will fail if geomID dosen't exist in coupled simulation
        * @param positionsOut Output container, is filled with all geometry node positions, must be pre-allocated to be as large as the number of nodes in the geometry
        */
        bool getAllGlobalNodePositions(int geomID, NApiEDEM::C3dPoint* positionsOut) const;

        /**
        * Get all global node velocities on a geometry
        * @param geomID The ID of the geometry we're looking for. Will fail if geomID dosen't exist in coupled simulation
        * @param velocitiesOut Output container, is filled with all geometry node velocities, must be pre-allocated to be as large as the number of nodes in the geometry
        */
        bool getAllGlobalNodeVelocities(int geomID, NApiEDEM::C3dVector* velocitiesOut) const;

        /**
        * Set a subset of node positions on a geometry in local space. Directly sets the node to this point immediately.
        * @param geomID The ID of the geometry we're looking for. Will fail if geomID dosen't exist in coupled simulation
        * @param numNodes Number of node positions to set. Must match the number of elements of nodeIndices, nodePositions, and optionally, deformationVelocitiesOverride
        * @param nodeIndices List of the node indices that we want to deform
        * @param nodePositions. Positions of the nodes that we want to deform. Must share structure of nodeIndices, and be the exact same size
        * @param deformationVelocitiesOverride. Optional paramater. If left empty, point velocities will be derived from the linear distance between old and new node positions.
        *                                       However, user can provide manual node velocities if they so desire, to alter deformation interaction behaviour.
        */
        bool setLocalNodePositions(int geomId, int numNodes, const int* nodeIndices, const NApiEDEM::C3dPoint* nodePositions, const NApiEDEM::C3dVector* deformationVelocitiesOverride = nullptr);

        /**
        * Set a subset of node positions on a geometry in global space. Directly sets the node to this point immediately.
        * @param geomID The ID of the geometry we're looking for. Will fail if geomID dosen't exist in coupled simulation
        * @param numNodes Number of node positions to set. Must match the number of elements of nodeIndices, nodePositions, and optionally, deformationVelocitiesOverride
        * @param nodeIndices List of the node indices that we want to deform
        * @param nodePositions. Positions of the nodes that we want to deform. Must share structure of nodeIndices, and be the exact same size
        * @param deformationVelocitiesOverride. Optional paramater. If left empty, point velocities will be derived from the linear distance between old and new node positions.
        *                                       However, user can provide manual node velocities if they so desire, to alter deformation interaction behaviour.
        */
        bool setGlobalNodePositions(int geomId, int numNodes, const int* nodeIndices, const NApiEDEM::C3dPoint* nodePositions, const NApiEDEM::C3dVector* deformationVelocitiesOverride = nullptr);

        /**
        * Offset a subset of node positions on a geometry in local space. Moves the nodes a set distance from their current position.
        * @param geomID The ID of the geometry we're looking for. Will fail if geomID dosen't exist in coupled simulation
        * @param numNodes Number of node positions to offset. Must match the number of elements of nodeIndices, nodePositions, and optionally, deformationVelocitiesOverride
        * @param nodeIndices List of the node indices that we want to deform
        * @param nodeOffsets Offsets that the geometry nodes will be moved by. Container must be the same size as the number of nodes of the selected geometry.
        * @param deformationVelocitiesOverride. Optional paramater. If left empty, point velocities will be derived from the linear distance between old and new node positions.
        *                                       However, user can provide manual node velocities if they so desire, to alter deformation interaction behaviour.
        */
        bool offsetLocalNodePositions(int geomId, int numNodes, const int* nodeIndices, const NApiEDEM::C3dPoint* nodeOffsets, const NApiEDEM::C3dVector* deformationVelocitiesOverride = nullptr);

        /**
        * Offset a subset of node positions on a geometry in global space. Moves the nodes a set distance from their current position.
        * @param geomID The ID of the geometry we're looking for. Will fail if geomID dosen't exist in coupled simulation
        * @param numNodes Number of node positions to offset. Must match the number of elements of nodeIndices, nodePositions, and optionally, deformationVelocitiesOverride
        * @param nodeIndices List of the node indices that we want to deform
        * @param nodeOffsets Offsets that the geometry nodes will be moved by. Container must be the same size as the number of nodes of the selected geometry.
        * @param deformationVelocitiesOverride. Optional paramater. If left empty, point velocities will be derived from the linear distance between old and new node positions.
        *                                       However, user can provide manual node velocities if they so desire, to alter deformation interaction behaviour.
        */
        bool offsetGlobalNodePositions(int geomId, int numNodes, const int* nodeIndices, const NApiEDEM::C3dPoint* nodeOffsets, const NApiEDEM::C3dVector* deformationVelocitiesOverride = nullptr);

        /*
        * Set all node positions on a geometry in local space. Directly sets the nodes to these points immediately.
        * @param geomID The ID of the geometry we're looking for. Will fail if geomID dosen't exist in coupled simulation
        * @param nodePositions Positions of the geometry nodes. Container must be the same size as the number of nodes of the selected geometry.
        * @param deformationVelocitiesOverride. Optional paramater. If left empty, point velocities will be derived from the linear distance between old and new node positions.
        *                                       However, user can provide manual node velocities if they so desire, to alter deformation interaction behaviour.
        */
        bool setAllLocalNodePositions(int geomID, const NApiEDEM::C3dPoint* nodePositions, const NApiEDEM::C3dVector* deformationVelocitiesOverride = nullptr);

        /**
        * Set all node positions on a geometry in global space. Directly sets the nodes to these points immediately.
        * @param geomID The ID of the geometry we're looking for. Will fail if geomID dosen't exist in coupled simulation
        * @param nodePositions Positions of the geometry nodes. Container must be the same size as the number of nodes of the selected geometry.
        * @param deformationVelocitiesOverride. Optional paramater. If left empty, point velocities will be derived from the linear distance between old and new node positions.
        *                                       However, user can provide manual node velocities if they so desire, to alter deformation interaction behaviour.
        */
        bool setAllGlobalNodePositions(int geomID, const NApiEDEM::C3dPoint* nodePositions, const NApiEDEM::C3dVector* deformationVelocitiesOverride = nullptr);


        /**
        * Offset all node positions on a geometry in local space. Moves the nodes a set distance from their current position.
        * @param geomID The ID of the geometry we're looking for. Will fail if geomID dosen't exist in coupled simulation
        * @param nodeOffsets Offsets that the geometry nodes will be moved by. Container must be the same size as the number of nodes of the selected geometry.
        * @param deformationVelocitiesOverride. Optional paramater. If left empty, point velocities will be derived from the linear distance between old and new node positions.
        *                                       However, user can provide manual node velocities if they so desire, to alter deformation interaction behaviour.
        */
        bool offsetAllLocalNodePositions(int geomID, const NApiEDEM::C3dPoint* nodeOffsets, const NApiEDEM::C3dVector* deformationVelocitiesOverride = nullptr);

        /**
        * Offset all node positions on a geometry in global space. Moves the nodes a set distance from their current position.
        * @param geomID The ID of the geometry we're looking for. Will fail if geomID dosen't exist in coupled simulation
        * @param nodeOffsets Offsets that the geometry nodes will be moved by. Container must be the same size as the number of nodes of the selected geometry.
        * @param deformationVelocitiesOverride. Optional paramater. If left empty, point velocities will be derived from the linear distance between old and new node positions.
        *                                       However, user can provide manual node velocities if they so desire, to alter deformation interaction behaviour.
        */
        bool offsetAllGlobalNodePositions(int geomID, const NApiEDEM::C3dPoint* nodeOffsets, const NApiEDEM::C3dVector* deformationVelocitiesOverride = nullptr);

        /**
        * Gets the number of particle->geometry contacts on a given geometry
        * So a client can allocate buffers of the correct size before calling getGeometryContacts
        *
        * @param geomId The target geometry ID, passing in -1 will return the number of contacts for all geometries
        * @param numContacts Output variable for the number of contacts the geometry has on it

        * @return True if succesful, false otherwise, likely the geomID couldn't be found
        */
        bool getNumGeometryParticleContacts(const int geomId, int& numContacts);

        /**
        * Returns arrays of information related to the particle->geometry contacts on passed in GeometryID.
        * Positions of contacts are handled globally. To build buffers, use getNumGeometryParticleContacts and build your buffers like this : auto contacts = new NApiFEA::CContactPrototype* [numOfParticleGeomContacts];
        *
        * @param geomId The target geometry ID, passing in -1 will return the contacts for all geometries
        * @param contacts Output buffer for the contacts found

        * @return True if succesful, false otherwise, likely the geomID couldn't be found
        */
        bool getGeometryParticleContacts(const int geomId, NApiFea::CContactPrototype* contacts);

       /**
        * Set the Type of the geometry section [Physical | Virtual | Dynamic Domain], to enable
        * use as a factory or as dynamic domain.
        *
        * Sent to EDEM:
        * @param sectionName the name of the geometry to be updated.
        * @param geometryType 1 == real geometry (i.e. have a physical presence)
        *                     2 == virtual geometry (used by factories)
        *                     3 == active geometry (used for dynamic domain)
        *
        * @return True if operation was successful, otherwise false.
        */
        bool setGeometryType(const char* sectionName, int geometryType);

        /**
        * Add a parent-child relationship between two geometries. 
        *
        * @param parentGeometryName Name of the geometry to set as the parent 
        * @param childGeometryName Name of the geometry to add a parent to
        * 
        * i.e if parentGeometryName = "parent" and childGeometryName = "child"
        * then the parent geometry of "child" will be "parent", and if parent
        * moves, so will child.
        *
        * @return True if operation was successful, otherwise false.
        */
        bool setTransformParent(const char* parentGeometryName, const char* childGeometryName);

        /**
         * Add a Conveyor Translation Kinematic to the currently selected geometry section
         *
         * @param geomId          Id of the target geometry
         * @param startTime       Kinematic start time
         * @param endTime         Kinematic end time
         * @param initialVelocity Kinematic initial velocity
         * @param acceleration    Kinematic acceleration
         * @param dirnXStart      The x-component of the direction start vector
         * @param dirnXEnd        The x-component of the direction end vector
         * @param dirnYStart      The y-component of the direction start vector
         * @param dirnYEnd        The y-component of the direction end vector
         * @param dirnZStart      The z-component of the direction start vector
         * @param dirnZEnd        The z-component of the direction end vector
         * @param displayVector   Flag to control the visibility of the direction vector
         * @param loop          Does the kinematic repeat
         * @param loopInterval  The time interval from the start time to the next start time when looping
         * @param loopUntilTime The time to loop until
         *
         * @return True if operation was successful, otherwise false.
         */
        bool addConveyorTranslationKinematic(int geomId, double startTime, double endTime, double initialVelocity, double acceleration,
                                             double dirnXStart, double dirnXEnd,
                                             double dirnYStart, double dirnYEnd,
                                             double dirnZStart, double dirnZEnd, bool displayVector,
                                             bool loop = false, double loopInterval = 0.0, double loopUntilTime = std::numeric_limits<double>().max());

        /**
         * Add a Conveyor Rotation Kinematic to the currently selected geometry section
         *
         * @param geomId          Id of the target geometry
         * @param startTime       Kinematic start time
         * @param endTime         Kinematic end time
         * @param initialVelocity Kinematic initial velocity
         * @param acceleration    Kinematic acceleration
         * @param rotnXStart      The x-component of the axis of rotation start vector
         * @param rotnXEnd        The x-component of the axis of rotation end vector
         * @param rotnYStart      The y-component of the axis of rotation start vector
         * @param rotnYEnd        The y-component of the axis of rotation end vector
         * @param rotnZStart      The z-component of the axis of rotation start vector
         * @param rotnZEnd        The z-component of the axis of rotation end vector
         * @param displayVector   Flag to control the visibility of the axis of rotation vector [true | false]
         * @param movesWithBody   Flag to control the the 'Moves with Body' behaviour [true | false]
         * @param poaAuto         Flag to control the 'Point of Action' behaviour: true = auto (default), false = manual
         * @param poaX            Point of Action x-component, only valid when poaAuto == false
         * @param poaY            Point of Action y-component, only valid when poaAuto == false
         * @param poaZ            Point of Action z-component, only valid when poaAuto == false
         * @param loop            Does the kinematic repeat
         * @param loopInterval    The time interval from the start time to the next start time when looping
         * @param loopUntilTime   The time to loop until
         *
         * @return True if operation was successful, otherwise false.
         */
        bool addConveyorRotationKinematic(int geomId, double startTime, double endTime, double initialVelocity, double acceleration,
                                          double rotnXStart, double rotnXEnd,
                                          double rotnYStart, double rotnYEnd,
                                          double rotnZStart, double rotnZEnd, bool displayVector,
                                          bool movesWithBody = true, bool poaAuto = true, double poaX = 0.0, double poaY = 0.0, double poaZ = 0.0,
                                          bool loop = false, double loopInterval = 0.0, double loopUntilTime = std::numeric_limits<double>().max());

        /**
         * Add a Linear Translation Kinematic to the currently selected geometry section
         *
         * @param geomId          Id of the target geometry
         * @param startTime       Kinematic start time
         * @param endTime         Kinematic end time
         * @param initialVelocity Kinematic initial velocity
         * @param acceleration    Kinematic acceleration
         * @param dirnXStart      The x-component of the direction start vector
         * @param dirnXEnd        The x-component of the direction end vector
         * @param dirnYStart      The y-component of the direction start vector
         * @param dirnYEnd        The y-component of the direction end vector
         * @param dirnZStart      The z-component of the direction start vector
         * @param dirnZEnd        The z-component of the direction end vector
         * @param displayVector   Flag to control the visibility of the direction vector
         * @param loop          Does the kinematic repeat
         * @param loopInterval  The time interval from the start time to the next start time when looping
         * @param loopUntilTime The time to loop until
         *
         * @return True if operation was successful, otherwise false.
         */
        bool addLinearTranslationKinematic(int geomId, double startTime, double endTime, double initialVelocity, double acceleration,
                                           double dirnXStart, double dirnXEnd,
                                           double dirnYStart, double dirnYEnd,
                                           double dirnZStart, double dirnZEnd, bool displayVector,
                                           bool loop = false, double loopInterval = 0.0, double loopUntilTime = std::numeric_limits<double>().max());

        /**
         * Add a Linear Rotation Kinematic to the currently selected geometry section
         *
         * @param geomId          Id of the target geometry
         * @param startTime       Kinematic start time
         * @param endTime         Kinematic end time
         * @param initialVelocity Kinematic initial velocity
         * @param acceleration    Kinematic acceleration
         * @param rotnXStart      The x-component of the axis of rotation start vector
         * @param rotnXEnd        The x-component of the axis of rotation end vector
         * @param rotnYStart      The y-component of the axis of rotation start vector
         * @param rotnYEnd        The y-component of the axis of rotation end vector
         * @param rotnZStart      The z-component of the axis of rotation start vector
         * @param rotnZEnd        The z-component of the axis of rotation end vector
         * @param displayVector   Flag to control the visibility of the axis of rotation vector [true | false]
         * @param movesWithBody   Flag to control the the 'Moves with Body' behaviour [true | false]
         * @param poaAuto         Flag to control the 'Point of Action' behaviour: true = auto (default), false = manual
         * @param poaX            Point of Action x-component, only valid when poaAuto == false
         * @param poaY            Point of Action y-component, only valid when poaAuto == false
         * @param poaZ            Point of Action z-component, only valid when poaAuto == false
         * @param loop            Does the kinematic repeat
         * @param loopInterval    The time interval from the start time to the next start time when looping
         * @param loopUntilTime   The time to loop until
         *
         * @return True if operation was successful, otherwise false.
         */
        bool addLinearRotationKinematic(int geomId, double startTime, double endTime, double initialVelocity, double acceleration,
                                        double rotnXStart, double rotnXEnd,
                                        double rotnYStart, double rotnYEnd,
                                        double rotnZStart, double rotnZEnd, bool displayVector,
                                        bool movesWithBody = true, bool poaAuto = true, double poaX = 0.0, double poaY = 0.0, double poaZ = 0.0,
                                        bool loop = false, double loopInterval = 0.0, double loopUntilTime = std::numeric_limits<double>().max());

        /**
         * Add a Sinusoidal Translation Kinematic to the currently selected geometry section
         *
         * @param geomId        Id of the target geometry
         * @param startTime     Kinematic start time
         * @param endTime       Kinematic end time
         * @param dirnXStart    The x-component of the direction start vector
         * @param dirnXEnd      The x-component of the direction end vector
         * @param dirnYStart    The y-component of the direction start vector
         * @param dirnYEnd      The y-component of the direction end vector
         * @param dirnZStart    The z-component of the direction start vector
         * @param dirnZEnd      The z-component of the direction end vector
         * @param displayVector Flag to control the visibility of the axis of rotation vector [true | false]
         * @param dispMag       The magnitude of the displacement
         * @param frequency     Frequency value
         * @param offset        Angular offset
         * @param loop          Does the kinematic repeat
         * @param loopInterval  The time interval from the start time to the next start time when looping
         * @param loopUntilTime The time to loop until
         *
         * @return True if operation was successful, otherwise false.
         */
        bool addSinusoidalTranslationKinematic(int geomId, double startTime, double endTime,
                                               double dirnXStart, double dirnXEnd,
                                               double dirnYStart, double dirnYEnd,
                                               double dirnZStart, double dirnZEnd, bool displayVector,
                                               double dispMag, double frequency, double offset,
                                               bool loop = false, double loopInterval = 0.0, double loopUntilTime = std::numeric_limits<double>().max());

        /**
         * Add a Sinusoidal Rotation Kinematic to the currently selected geometry section
         *
         * @param geomId        Id of the target geometry
         * @param startTime     Kinematic start time
         * @param endTime       Kinematic end time
         * @param rotnXStart    The x-component of the axis of rotation start vector
         * @param rotnXEnd      The x-component of the axis of rotation end vector
         * @param rotnYStart    The y-component of the axis of rotation start vector
         * @param rotnYEnd      The y-component of the axis of rotation end vector
         * @param rotnZStart    The z-component of the axis of rotation start vector
         * @param rotnZEnd      The z-component of the axis of rotation end vector
         * @param displayVector Flag to control the visibility of the axis of rotation vector [true | false]
         * @param dispMag       The magnitude of the displacement
         * @param frequency     Frequency value
         * @param offset        Angular offset
         * @param displayVector Flag to control the visibility of the axis of rotation vector [true | false]
         * @param movesWithBody Flag to control the the 'Moves with Body' behaviour [true | false]
         * @param poaAuto       Flag to control the 'Point of Action' behaviour: true = auto (default), false = manual
         * @param poaX          Point of Action x-component, only valid when poaAuto == false
         * @param poaY          Point of Action y-component, only valid when poaAuto == false
         * @param poaZ          Point of Action z-component, only valid when poaAuto == false
         * @param loop          Does the kinematic repeat
         * @param loopInterval  The time interval from the start time to the next start time when looping
         * @param loopUntilTime The time to loop until
         *
         * @return True if operation was successful, otherwise false.
         */
        bool addSinusoidalRotationKinematic(int geomId, double startTime, double endTime,
                                            double rotnXStart, double rotnXEnd,
                                            double rotnYStart, double rotnYEnd,
                                            double rotnZStart, double rotnZEnd, bool displayVector,
                                            double dispMag, double frequency, double offset,
                                            bool movesWithBody = true, bool poaAuto = true, double poaX = 0.0, double poaY = 0.0, double poaZ = 0.0,
                                            bool loop = false, double loopInterval = 0.0, double loopUntilTime = std::numeric_limits<double>().max());

        /**
         * Enables the material type for a specified geometry section to be updated
         *
         * @param sectionId target geometry section to be updated
         * @param materialId index of the material to be assigned
         * @return true / false
         */
        bool setSectionMaterial(int sectionId, int materialId);

        /**
         * This function enables a specified geometry section to be removed from the simulation
         *
         * @param geometryName Geometry section name
         * @return True if operation was successful, otherwise false.
         */
        bool removeGeometry(const char* geometryName);

        /**
         * Select to load an existing deck in EDEM
         *
         * Sent to EDEM:
         * @param filename The filename, including path, of the EDEM deck
         *
         * Returned from EDEM:
         * @return True if operation was successful, otherwise false.
         */
        bool selectDeck(const char* filename);

        /**
         * Get the full path to the currently loaded simulation (.dem) file
         * 
         * Sent to EDEM:
         * @param filename Uninitialised char pointer to write the currently loaded simulation path to
         *
         * Returned from EDEM:
         * @return True if operation was successful, otherwise false.
         */
        bool getSelectedDeck(char*& filename);

        /**
         * Retrieve the simulation's domain parameters
         *
         * Sent to EDEM:
         * @param xmin - min x position
         * @param ymin - min y position
         * @param zmin - min z position
         * @param xmax - max x position
         * @param ymax - max y position
         * @param zmax - max z position
         *
         * Returned from EDEM:
         * @return True if operation was successful, otherwise false.
         */
        bool getDomain(double& xmin, double& ymin, double& zmin, double& xmax, double& ymax, double& zmax);

        /**
         * Adjust the simulation's domain parameters
         *
         * Sent to EDEM:
         * @param xmin - min x position
         * @param ymin - min y position
         * @param zmin - min z position
         * @param xmax - max x position
         * @param ymax - max y position
         * @param zmax - max z position
         *
         * Returned from EDEM:
         * @return True if operation was successful, otherwise false.
         */
        bool setDomain(double xmin, double ymin, double zmin, double xmax, double ymax, double zmax);

        /**
         * Get the gravity vector in EDEM for your simulation
         *
         * Sent to EDEM:
         * @param gravity A gravity vector
         *
         * Returned from EDEM:
         * @return True if operation was successful, otherwise false.
         */
        bool getGravity(NApiEDEM::C3dValue& gravity);

        /**
         * Set the gravity vector in EDEM for your simulation
         *
         * Sent to EDEM:
         * @param gravity A gravity vector
         *
         * Returned from EDEM:
         * @return True if operation was successful, otherwise false.
         */
        bool setGravity(const NApiEDEM::C3dValue& gravity);

        /**
        * Set the auto grid resizing state
        *
        * Sent to EDEM:
        * @param state true (on), false (off)
        *
        * Returned from EDEM:
        * @return true if operation was successful, otherwise false.
        */
        bool setAutoGridResizing(bool state);

        /**
         * Register a new custom property for EDEM to use
         * Sent to EDEM:
         * @param name Name of the new custom property
         * @param numberElements Number of elements that make up a particle custom
         *                         property e.g. 1 for a scalar property, 3 for a 3D
         *                         vector property
         * @param unitType Index for the SI units for the property
         * @param initialValue Initial value for the property
         * @param dataType The data type is limited to double only (0)
         *
         * Returned from EDEM:
         * @param index EDEM returns a unique custom property index as an identifier
         * @return True if operation was successful, otherwise false.
         */
        bool registerCustomProperty(const char* name,
                                    const int& numberElements,
                                    const int& unitType,
                                    const double& initialValue,
                                    int& index,
                                    const int dataType = 0);



/////////////////////////////////////////////////////////////////////////////////////////
//                                 Simulation Commands                                 //
/////////////////////////////////////////////////////////////////////////////////////////

        /**
         * Request EDEM to perform some time-step calculations.
         *
         * For V2_0_0 onwards it is recommended to set this variable to take advantage of the
         * simulator pause feature. Performance and memory usage are significantly improved.
         * See the Coupling Interface Programming guide for further details
         *
         * Sent to EDEM:
         * @param simTimeStep The amount time you wish EDEM to simulate
         *                      (strongly recommended to be a multiple of the EDEM time-step being used)
         * @param totalTime Total sim time can be entered to allow EDEM simulator to pause
         *                    rather than stop between simulation steps.
         * Returned from EDEM:
         * @return True if operation was successful, otherwise false.
         */
        bool simulate(const double& simTimeStep, const double totalTime = -1.0);

        /**
         * Request EDEM to perform some time-step calculations
         *
         * This additional simulate method allows users to easily simulate to multiples of the
         * EDEM time-step
         *
         * For V2_0_0 onwards it is recommended to set this variable to take advantage of the
         * simulator pause feature. Performance and memory usage are significantly improved.
         * See the Coupling Interface Programming guide for further details
         *
         * Sent to EDEM:
         * @param totalTime Total sim time can be entered to allow EDEM simulator to pause
         *                    rather than stop between simulation steps.
         * @param simulateForNumTimeSteps The number of time-steps that you wish EDEM to simulate for
         *
         *
         * Returned from EDEM:
         * @return True if operation was successful, otherwise false.
         */
        bool simulate(const int simulateForNumTimeSteps = 1, const double totalTime = -1.0);

        /**
         * Send EDEM a stop simulation request
         * @return True if operation was successful, otherwise false.
         */
        bool stopSimulation();

        /**
         * Get the elapsed simulation time from EDEM
         *
         * Returned from EDEM:
         * @param time Current elapsed simulation time in EDEM
         * @return True if operation was successful, otherwise false.
         */
        bool getEDEMTime(double& time);

        /**
         * Set the point in simulation time that EDEM is at. Simulation will commence from
         * this point when started
         *
         * Sent to EDEM:
         * @param time Time that EDEM is set to
         *
         * Returned from EDEM:
         * @return True if operation was successful, otherwise false.
         */
        bool setEDEMTime(const double& time);

        /**
         * Set the time-step for the simulation. Fails when auto time step is selected.
         *
         * Sent to EDEM:
         * @param timeStep Time-step to be used for the simulation
         *
         * Returned from EDEM:
         * @return True if operation was successful, otherwise false.
         */
        bool setEDEMTimeStep(const double& timeStep);

        /**
         * Set the Data Save Interval for the simulation
         *
         * Sent to EDEM:
         * @param saveInterval Target save interval for the simulation
         *
         * Returned from EDEM:
         * @return True if operation was successful, otherwise false.
         */
        bool setSaveInterval(const double& saveInterval);

        /**
         * Set the grid cell size for the simulation
         *
         * Sent to EDEM:
         * @param cellSize Grid cell size to be used for the simulation
         *
         * Returned from EDEM:
         * @return True if operation was successful, otherwise false.
         */
        bool setGridCellSize(const double& cellSize);

        /**
         * Set the process core count for the simulation
         *
         * Sent to EDEM:
         * @param coreCount Number of processor cores to be used for the simulation
         *
         * Returned from EDEM:
         * @return True if operation was successful, otherwise false.
         */
        bool setNumberOfCores(const int& coreCount);

        /**
         * Get the time-step currently set for the simulation
         *
         * Returned from EDEM:
         * @param timeStep The time-step currently used by EDEM
         * @return True if operation was successful, otherwise false.
         */
        bool getEDEMTimeStep(double& timeStep);

        /**
         * Get the timesteps associated with the simulation
         * Note: The buffer size should be set to 'TIMESTEP_LIMIT' as defined in
         * the API types header file
         *
         * Returned from EDEM:
         * @param edemTimesteps List of available timesteps
         * @return True if operation was successful, otherwise false.
         */
        bool getEDEMTimesteps(double* edemTimesteps);

        /**
         * Get all the timesteps associated with the simulation
         * Note: The buffer size should be set to 'TIMESTEP_LIMIT' as defined in
         * the API types header file
         *
         * Returned from EDEM:
         * @param edemTimesteps List of available timesteps
         * @param numTimesteps the number of timesteps in the simulation
         * @return True if operation was successful, otherwise false.
         */
        bool getEDEMTimesteps(double* edemTimesteps, int& numTimesteps);

        /**
         * As before, with the addition of enabling the user to specify the size of
         * the buffer to use for storing the timesteps data.
         *
         * Returned from EDEM:
         * @param edemTimesteps List of available timesteps, containing bufferSize entries
         * @param numTimesteps Number of timesteps in the simulation
         * @param bufferSize Size of the array for storing the retrieved timesteps
         * @return True if operation was successful, otherwise false.
         */
        bool getEDEMTimesteps(double* edemTimesteps, unsigned int& numTimesteps, const unsigned int bufferSize);

        /**
         * Use this function to determine the overall number of timesteps in the simulation. Use in
         * conjunction with the getEDEMTimesteps(double*, unsigned int&, const unsigned int)
         * variant to ensure that the required buffer size is configured.
         *
         * Params:
         * @param numTimesteps number of timesteps in the simulation
         * @return True if operation was successful, otherwise false.
         */
        bool getNumberOfTimesteps(unsigned int& numTimesteps);

        /**
         * Retrieves the value for the total simulation time as configured in the
         * GUI's Simulation Time : Total Time field.
         *
         * Params:
         * @param totalSimTime The total time for the simulation run.
         * @return True if operation was successful, otherwise false.
         */
        bool getTotalSimulationTime(double& totalSimTime);

        /**
         * Exports the current timestep to a new simulation deck with a specified timestep value.
         * Params:
         * @param deckname The full path and name for the new deck to be created.
         * @param timestepValue The initial timestep value for the newly created deck.
         * @param makeActive Whether or not to change the currently active deck to the newly created one.
         * @param path If specified, the path to the location to save the newly exported deck to, a trailing '/' is optional for the path.
         * @return True if operation was successful, otherwise false.
         */
        bool exportTimeStepToNewDeck(const char* deckname, const double timestepValue, bool makeActive, const char* path = nullptr);

/////////////////////////////////////////////////////////////////////////////////////////
//                           Particle Interaction Commands                             //
/////////////////////////////////////////////////////////////////////////////////////////

        /**
         * Get the data for all particles in the simulation
         *
         * Returned from EDEM:
         * @param data Pointer to a user allocated array of CDiscreteElement objects
         * CAUTION - This data is not automatically deleted. The user has
         *           responsibility for deleting particle data when it is no
         *           longer required
         *
         * Returned from EDEM:
         * @return True if operation was successful, otherwise false.
         */
        bool getParticleData(NApiCfd::CDiscreteElement* data);

        /**
         * Get the number of particle types
         *
         * Returned from EDEM:
         * @return Returns number of particle types. Returns -1 if data was not obtained
         */
        int getNumParticleTypes();

        /**
         * Get the number of particle of a specified type. Using the
         * default value (-1) will return the number of particles
         * in the simulation of all types
         *
         * Sent to EDEM:
         * @param particleType Particle type index.
         *
         * Returned from EDEM:
         * @return Returns number of particles of that type. Returns -1 if data was not obtained
         */
        int getNumParticles(const int& particleType = -1);

        /**
         * Get the data for all particle prototypes in the simulation.
         * These are the base particles that all other particles are based upon.
         *
         * Returned from EDEM:
         * @param prototypeData Pointer to a user allocated array of CElementPrototype objects
         * CAUTION - This data is not automatically deleted. The user has
         *           responsibility for deleting prototype data when it is no
         *           longer required.
         *
         * Returned from EDEM:
         * @return True if operation was successful, otherwise false.
         */
        bool getParticlePrototypeData(NApiCfd::CElementPrototype* prototypeData);

        /**
         * Get the data for all spheres asscoiated with one prototype in the simulation.
         * These are the surphaces that make up a particle.
         *
         * @param prototypeID: Id value of the particle prototype.
         *
         * Returned from EDEM:
         * @param sphereData Pointer to a user allocated array of CParticleSphere objects
         * CAUTION - This data is not automatically deleted. The user has
         *           responsibility for deleting prototype data when it is no
         *           longer required.
         *
         * Returned from EDEM:
         * @return True if operation was successful, otherwise false.
         */
        bool getPrototypeSpheres(const unsigned int prototypeID, NApiCfd::CParticleSphere* sphereData);

        /**
         * Get the number of surfaces of a specified type.
         * Sent to EDEM:
         * @param prototypeID id number associated with parent particle prototype.
         *
         * Returned from EDEM:
         * @return Returns number of surfaces of that prototype. Returns -1 if data was not obtained
         */
        int getTotalPrototypeSpheres(const unsigned int prototypeID);

        /**
         * Get values for custom property from EDEM by particle type
         *
         * Sent to EDEM:
         * @param numParticles The total number of particles in the simulation
         * @param propertyIndex The property index identifying the custom property
         * @param numPropElements The number of elements making up the property
         *
         * Returned from EDEM:
         * @param data Pointer to a user allocated array used to store the data
         * CAUTION - This data is not automatically deleted. The user has responsibility for deleting
         *           custom property data when it is no longer required
         * @return True if operation was successful, otherwise false.
         */
        bool getValueForProperty(const int& numParticles,
                                 const int& propertyIndex,
                                 const int& numPropElements,
                                 double*& data);

        /**
         * Get an array of particle sample points for a specified particle type
         *
         * Sent to EDEM:
         * @param samples Number of sample points to collect
         * @param type Particle type index you wish to retrieve
         *
         * Returned from EDEM:
         * @param samplePoints A pointer to a user allocated array. 3(D) times n-sample points in size
         * CAUTION - This data is not automatically deleted. The user has responsibility for deleting
         *           particle data when it is no longer required
         * @return True if operation was successful, otherwise false.
         */
        bool getParticleTypeSamplePoints(double* samplePoints,
                                         const int& samples,
                                         const int& type);

        /**
         * Set the drag force and torque on each particle using arrays
         * of forces and torques. See EDEM CFD Coupling: Programming Guide
         * for further documentation
         *
         * Sent to EDEM:
         * @param numParticles the number of particles in the simulation
         * @param force A pointer to an array of 3D force vectors
         * @param torque A pointer to an array of 3D torque vectors
         *
         * Returned from EDEM:
         * @return True if operation was successful, otherwise false.
         */
        bool setForceAndTorque(int numParticles, double* force, double* torque);

        /**
         * Set the position of the particles in the simulation
         *
         * Sent to EDEM:
         * @param particleIDs vector of particle IDs to affect
         * @param newPosition the new point value to set as the position of the particle
         * @param newValueAccumType NApi::EValueAccumulationType the new way to apply values, options include
                    -> eOverWrite (default) : Flat writes over the prior value
                    -> eAdditive            : Adds the value onto the prior value
                    -> eMultiplicative      : Does nothing for Position

         * Returned from EDEM:
         * @return True if operation was successful, otherwise false.
         */
        bool setPosition(const std::vector<int>& particleIDs,
                         const NApiEDEM::C3dPoint& newPosition,
                         const unsigned int newValueAccumType = 0u);

        /**
         * Set the scale of the particles in the simulation
         *
         * Sent to EDEM:
         * @param particleIDs vector of particle IDs to affect
         * @param scale the new double value to rescale the particles with
         * @param newValueAccumType NApi::EValueAccumulationType the new way to apply values, options include
                    -> eOverWrite (default) : Flat writes over the prior value
                    -> eAdditive            : Adds the value onto the prior value
                    -> eMultiplicative      : Multiplies old value by new value
         *
         * Returned from EDEM:
         * @return True if operation was successful, otherwise false.
         */
        bool setScale(const std::vector<int>& particleIDs,
                      const double scale,
                      const unsigned int newValueAccumType = 0u);

        /**
         * Set the velocity of the particles in the simulation
         *
         * Sent to EDEM:
         * @param particleIDs vector of particle IDs to affect
         * @param newVelocity the new point value to set as the velocity of the particle
         * @param newValueAccumType NApi::EValueAccumulationType the new way to apply values, options include
                    -> eOverWrite (default) : Flat writes over the prior value
                    -> eAdditive            : Adds the value onto the prior value
                    -> eMultiplicative      : Does nothing for Velocity

         * Returned from EDEM:
         * @return True if operation was successful, otherwise false.
         */
        bool setVelocity(const std::vector<int>& particleIDs,
                         const NApiEDEM::C3dVector& newVelocity,
                         const unsigned int newValueAccumType = 0u);

        /**
         * Set values for custom property from EDEM by particle type
         *
         * @param numParticles The total number of particles in the simulation
         * @param propertyIndex The property index identifying the custom property
         * @param numPropElements The number of elements making up the property
         * @param data Pointer to the memory used to store the custom property data
         *
         * Returned from EDEM:
         * @return True if operation was successful, otherwise false..
         */
        bool setValueForProperty(const int& numParticles,
                                 const int& propertyIndex,
                                 const int& numPropElements,
                                 double* data);

/////////////////////////////////////////////////////////////////////////////////////////
//                                 GUI Interactions                                    //
/////////////////////////////////////////////////////////////////////////////////////////

        /**
         * Method displays the Creator in EDEM
         *
         * Returned from EDEM:
         * @return True if operation was successful, otherwise false..
         */
        bool showCreator();

        /**
         * Method displays the Simulator in EDEM
         *
         * Returned from EDEM:
         * @return True if operation was successful, otherwise false..
         */
        bool showSimulator();

        /**
         * Method displays the Analyst in EDEM
         *
         * Returned from EDEM:
         * @return True if operation was successful, otherwise false..
         */
        bool showAnalyst();

        /**
         * Method allows the user to deliberately disable warning pop-up dialogues when the
         * simulation is starting, for convenience. This method removes dialogues that warn
         * the user that existing EDEM data will be overwritten!
         *
         * @param disabled boolean value to disable/ re-enable GUI warnings in EDEM
         *
         * Returned from EDEM:
         * @return True if operation was successful, otherwise false..

         */
        bool disableGuiWarnings(bool disabled);

/////////////////////////////////////////////////////////////////////////////////////////
//                                 Dynamics Methods                                    //
/////////////////////////////////////////////////////////////////////////////////////////

        /**
         * REGISTER THE GEOMETRY FOR CONTROL by through the EDEM Coupling Interface and
         * get the geometry int ID identifier for the corresponding geometry name
         *
         * @param geomName A pointer to an array of char*[128] to hold the geometry names
         * @param id The unique ID corresponding to the geomName, returned
         * @return True if operation was successful, otherwise false.
         */
        bool getGeometryId(const char* geomName, int& id);

        /**
         * Rename the required geometry section
         *
         * @param oldName The exisiting name of the geometry section
         * @param newName The new name for the geometry section
         * @return pass / fail depending on the success of the operation
         */
        bool renameGeometrySection(const char* oldName, const char* newName);

        /**
         * Get the position of geometry specified by its ID at the current simulation time-step
         *
         * @param id The geometry ID that position is to be obtained for
         * @param centreOfMass A reference to a C3dValue position of the geometry centre of mass
         * @param orientation A reference to a C3x3Matrix orientation of the geometry
         *
         * @return True if operation was successful, otherwise false.
         */
        bool getGeometryPosition(const int id, NApiEDEM::C3dValue& centreOfMass, NApiEDEM::C3x3Matrix& orientation);

        /**
         * Get the position of the point of action the geometry is currently moving about. The
         * default point of action is the same as the centre of mass of the geometry
         *
         * @param id The geometry ID for the point of action
         * @param pointOfAction A reference to a C3dValue point of action for the geometry
         *
         * @return True if operation was successful, otherwise false.
         */
        bool getGeometryPointOfAction(const int id, NApiEDEM::C3dValue& pointOfAction);

        /**
         * Get the current linear and angular velocities of geometry specified by its ID
         *
         * @param id The geometry ID that position is to be obtained for
         * @param velocity A reference to the C3dValue velocity of the geometry
         * @param angVelocity A reference to the C3dValue angular velocity of the geometry
         *
         * @return True if operation was successful, otherwise false.
         */
        bool getGeometryVelocity(const int id, NApiEDEM::C3dValue& velocity, NApiEDEM::C3dValue& angVelocity);

        /**
         * Get the force and torque that acts upon a specified geometry
         *
         * @param id The geometry ID for that forces are required for
         * @param force A reference to a C3dValue force acting on geometry
         * @param torque A reference to a C3dValue torque acting on geometry about
         *                 the specified point of action specified for the simulation
         *
         * @return True if operation was successful, otherwise false.
         */
        bool getGeometryForces(const int id, NApiEDEM::C3dValue& force, NApiEDEM::C3dValue& torque);

        /**
         * Set the point of action for a given geometry if rotational motion is performed around a point
         * other than the centre of the mass of the object
         *
         * @param id The geometry ID for that the point of action is being set for
         * @param pointOfAction A reference to a C3dValue containing the value of the point of action
         *
         * @return True if operation was successful, otherwise false.
         */
        bool setGeometryPointOfAction(const int id, NApiEDEM::C3dValue& pointOfAction);

        /**
         * Set the point to translate the geometry to. The orientation to move the geometry to. The point of action
         * for the rotation. The velocity and angular velocities. Specify the time the geometry motion is required
         * to take.
         *
         * @param id The ID of the geometry to be moved
         * @param totalTranslation The position vector that the geometry should be translated to
         * @param orientation The orientation matrix that geometry should be rotated to
         * @param velocity The velocity associated with the geometry. This parameter has no effect on the motion of the geometry
         *                   it is used in contact models during the resolution of contact
         * @param angularVelocity The angular velocity of the geometry. This parameter has no effect on the motion of the geometry
         *                          it is used in contact models during the resolution of contact
         * @param actionTime The simulation time period over which the geometry motion should take place (Should be a multiple of
         *               the EDEM time-steps
         * @param movePoA The point of action about which rotation should occur moves with the translation of the geometry
         *
         * @return True if operation was successful, otherwise false.
         */
        bool setGeometryMotion(const int id,
                               const NApiEDEM::C3dValue& totalTranslation,
                               const NApiEDEM::C3x3Matrix& orientation,
                               const NApiEDEM::C3dValue& velocity,
                               const NApiEDEM::C3dValue& angularVelocity,
                               const double actionTime,
                               bool movePoA = true);

        /**
         * Get the total translation of the target geometry. This functionality should be
         * utilised when a simulation is following a sequence of start-stop-restart iterations
         *
         * @param id The target geometry ID
         * @param totalTranslation A reference to a C3dValue translation associated with the geometry
         *
         * @return True if operation was successful, otherwise false.
         */
        bool getGeometryTranslation(const int id, NApiEDEM::C3dValue& totalTranslation);

        /**
        * Get the geometry CAD initial rotation.
        *
        * Sent to EDEM:
        * @param id The target geometry ID
        *
        * Returned from EDEM:
        * @param orientation The initial orientation matrix of the geometry.
        *
        * @return True if operation was successful, otherwise false.
        */
        bool getGeometryCADInitialRotation(const int id, NApiEDEM::C3x3Matrix& orientation);


/////////////////////////////////////////////////////////////////////////////////////////
//                             Data Extraction Commands                                //
/////////////////////////////////////////////////////////////////////////////////////////

        /**
         * Will generate one AXDT file of either pressure or forces data
         * applied to the specified geometry. Data is linearlly averaged from
         * startTime to endTime. A startTime equal endTime is permissable.
         * @param targetPath The file that the extracted data will be stored in.
         * @param geometryName The name of geometry as supplied by the deck.
         * @param extractionType 0x0 - pressure
         *                       0x1   force
         * @param startTime The timestep to begin extraction.
         * @param endTime   The timestep to end extraction.
         * @param align If true, moving geometries will have their forces / pressures
         *                    realligned to CAD geometry positions. If false will be alligned
         *                    with global vertex positions.
         */
        bool extractGeometryAXDT(const char* targetPath,
                                 const char* geometryName,
                                 int extractionType,
                                 double startTime,
                                 double endTime,
                                 bool align = true);


        /////////////////////////////////////////////////////////////////////////////////////////
        //                             Deprecated Commands                                     //
        /////////////////////////////////////////////////////////////////////////////////////////

        /**
         * Add a Sinusoidal Translation Kinematic to the currently selected geometry section
         *
         * @param geomId    Id of the target geometry
         * @param startTime Kinematic start time
         * @param endTime   Kinematic end time
         * @param dispX     The x-component of the displacement
         * @param dispY     The y-component of the displacement
         * @param dispZ     The z-component of the displacement
         * @param frequency Frequency value
         * @param offset    Angular offset
         * @param loop          Does the kinematic repeat
         * @param loopInterval  The time interval from the start time to the next start time when looping
         * @param loopUntilTime The time to loop until
         *
         * @return True if operation was successful, otherwise false.
         */
        DEPRECATED bool addSinusoidalTranslationKinematic(int geomId, double startTime, double endTime,
                                                          double dispX, double dispY, double dispZ,
                                                          double frequency, double offset,
                                                          bool loop = false, double loopInterval = 0.0, double loopUntilTime = std::numeric_limits<double>().max());

        /**
         * Add a Sinusoidal Rotation Kinematic to the currently selected geometry section
         *
         * @param geomId        Id of the target geometry
         * @param startTime     Kinematic start time
         * @param endTime       Kinematic end time
         * @param dispX         The x-component of the displacement
         * @param dispY         The y-component of the displacement
         * @param dispZ         The z-component of the displacement
         * @param frequency     Frequency value
         * @param offset        Angular offset
         * @param poaX          Point of Action x-component
         * @param poaY          Point of Action y-component
         * @param poaZ          Point of Action z-component
         * @param movesWithBody Flag to control the the 'Moves with Body' behaviour [true | false]
         * @param loop          Does the kinematic repeat
         * @param loopInterval  The time interval from the start time to the next start time when looping
         * @param loopUntilTime The time to loop until
         *
         * @return True if operation was successful, otherwise false.
         */
        DEPRECATED bool addSinusoidalRotationKinematic(int geomId, double startTime, double endTime,
                                                       double dispX, double dispY, double dispZ,
                                                       double frequency, double offset,
                                                       double poaX = 0.0, double poaY = 0.0, double poaZ = 0.0,
                                                       bool movesWithBody = true,
                                                       bool loop = false, double loopInterval = 0.0, double loopUntilTime = std::numeric_limits<double>().max());

        /**
         * Add a Linear Translation Dynamic to the currently selected geometry section
         * Note: This function is deprecated as of version 3.0.0 of the coupling
         *
         * @param geomId          Id of the target geometry
         * @param startTime       Dynamic start time
         * @param endTime         Dynamic end time
         * @param initialVelocity Dynamic initial velocity
         * @param acceleration    Dynamic acceleration
         * @param dirnXStart      The x-component of the direction start vector
         * @param dirnXEnd        The x-component of the direction end vector
         * @param dirnYStart      The y-component of the direction start vector
         * @param dirnYEnd        The y-component of the direction end vector
         * @param dirnZStart      The z-component of the direction start vector
         * @param dirnZEnd        The z-component of the direction end vector
         * @param displayVector   Flag to control the visibility of the direction vector
         *
         * @return True if operation was successful, otherwise false.
         */
        DEPRECATED bool addLinearTranslationDynamic(int geomId, double startTime, double endTime, double initialVelocity, double acceleration,
                                                    double dirnXStart, double dirnXEnd, double dirnYStart, double dirnYEnd,
                                                    double dirnZStart, double dirnZEnd, bool displayVector);

        /**
         * Add a Linear Rotation Dynamic to the currently selected geometry section
         * Note: This function is deprecated as of version 3.0.0 of the coupling
         *
         * @param geomId          Id of the target geometry
         * @param startTime       Dynamic start time
         * @param endTime         Dynamic end time
         * @param initialVelocity Dynamic initial velocity
         * @param acceleration    Dynamic acceleration
         * @param rotnXStart      The x-component of the axis of rotation start vector
         * @param rotnXEnd        The x-component of the axis of rotation end vector
         * @param rotnYStart      The y-component of the axis of rotation start vector
         * @param rotnYEnd        The y-component of the axis of rotation end vector
         * @param rotnZStart      The z-component of the axis of rotation start vector
         * @param rotnZEnd        The z-component of the axis of rotation end vector
         * @param displayVector   Flag to control the visibility of the axis of rotation vector [true | false]
         * @param movesWithBody   Flag to control the the 'Moves with Body' behaviour [true | false]
         * @param poaAuto         Flag to control the 'Point of Action' behaviour: true = auto (default), false = manual
         * @param poaX            Point of Action x-component, only valid when poaAuto == false
         * @param poaY            Point of Action y-component, only valid when poaAuto == false
         * @param poaZ            Point of Action z-component, only valid when poaAuto == false
         *
         * @return True if operation was successful, otherwise false.
         */
        DEPRECATED bool addLinearRotationDynamic(int geomId, double startTime, double endTime, double initialVelocity, double acceleration,
                                                 double rotnXStart, double rotnXEnd, double rotnYStart, double rotnYEnd,
                                                 double rotnZStart, double rotnZEnd, bool displayVector,
                                                 bool movesWithBody = true, bool poaAuto = true, double poaX = 0.0, double poaY = 0.0, double poaZ = 0.0);

        /**
         * Add a Sinusoidal Translation Dynamic to the currently selected geometry section
         * Note: This function is deprecated as of version 3.0.0 of the coupling
         *
         * @param geomId    Id of the target geometry
         * @param startTime Dynamic start time
         * @param endTime   Dynamic end time
         * @param dispX     The x-component of the displacement
         * @param dispY     The y-component of the displacement
         * @param dispZ     The z-component of the displacement
         * @param frequency Frequency value
         * @param offset    Angular offset
         *
         * @return True if operation was successful, otherwise false.
         */
        DEPRECATED bool addSinusoidalTranslationDynamic(int geomId, double startTime, double endTime,
                                                        double dispX, double dispY, double dispZ,
                                                        double frequency, double offset);

        /**
         * Add a Sinusoidal Rotation Dynamic to the currently selected geometry section
         * Note: This function is deprecated as of version 3.0.0 of the coupling
         *
         * @param geomId        Id of the target geometry
         * @param startTime     Dynamic start time
         * @param endTime       Dynamic end time
         * @param dispX         The x-component of the displacement
         * @param dispY         The y-component of the displacement
         * @param dispZ         The z-component of the displacement
         * @param frequency     Frequency value
         * @param offset        Angular offset
         * @param poaX          Point of Action x-component
         * @param poaY          Point of Action y-component
         * @param poaZ          Point of Action z-component
         * @param movesWithBody Flag to control the the 'Moves with Body' behaviour [true | false]
         *
         * @return True if operation was successful, otherwise false.
         */
        DEPRECATED bool addSinusoidalRotationDynamic(int geomId, double startTime, double endTime,
                                                     double dispX, double dispY, double dispZ,
                                                     double frequency, double offset,
                                                     double poaX = 0.0, double poaY = 0.0, double poaZ = 0.0,
                                                     bool movesWithBody = true);

        /**
        * Set the Type of the geometry section [Physical | Virtual], to enable
        * use as a factory.
        *
        * Sent to EDEM:
        * @param sectionName the name of the geometry to be updated.
        * @param isVirtual true == virtual / false == physical.
        *
        * @return True if operation was successful, otherwise false.
        */
        DEPRECATED bool setGeometryType(const char* sectionName, bool isVirtual = true);

        /**
        * Get the Type of the geometry section [Physical | Virtual]
        *
        * Sent to EDEM:
        * @param sectionName the name of the geometry to be updated.
        * @param isVirtual (retrieved) true == virtual / false == physical.
        *
        * @return True if operation was successful, otherwise false.
        */
        DEPRECATED bool getGeometryType(const char* sectionName, bool& isVirtual);

        /**
        * For a given geometry, get the node IDs and their forces.
        * Setting id = -1, results will be corresponding to all the geometry groups.
        * This function is recommended to be used only for post-processing reasons.
        * Its accuracy is very low. For high accuracy use getTrianglesIDsAndForces instead.
        *
        * @param id The target geometry ID
        * @param nodesIDs The node IDs of the given geometry.
        * @param nodeForces The node forces of the given geometry.
        *
        * @return True if operation was successful, otherwise false.
        */
        DEPRECATED bool getNodeIDsAndForces(const int id, int* nodesIDs, double* nodeForces);
        
        /**
        * Enables various geometry options to be configured prior to
        * invoking the loadGeometry() function
        *
        * @param method Curvature | Quality / true | false
        * @param facetSag Facet sag value - applies to Quality method
        * @param facetLength Facet length value - applies to Quality method
        * @param facetCount The minimum number of facets - applies to Quality method
        *
        * Returned from EDEM:
        * @return True if import was successful, otherwise false.
        */
        DEPRECATED bool setGeometryImportParameters(bool /*method*/,
                                                    double /*facetSag*/,
                                                    double /*facetLength*/,
                                                    int /*facetCount*/);


    };
    /** @} */
}

#endif  //IEDEMCOUPLING_H
